/*
 * Copyright 2005-2013 rsico. All rights reserved.
 * Support: http://www.rsico.cn
 * License: http://www.rsico.cn/license
 */
package com.rzico.market.plugin;

import com.rzico.core.entity.SysFile;
import com.rzico.core.entity.SysPlugin;
import com.rzico.core.model.PluginAttribute;
import com.rzico.core.plugin.PaymentPlugin;
import com.rzico.core.service.SysFileService;
import com.rzico.core.service.SysPluginService;
import com.rzico.market.entity.MarketProduct;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * Plugin - 第三方插件
 * @author rsico Team
 * @version 3.0
 */
@SuppressWarnings("deprecation")
@Slf4j
public abstract class MarketPlugin implements Comparable<MarketPlugin> {


	@Autowired @Lazy
	public SysPluginService sysPluginService;

	@Autowired
	public SysFileService sysFileService;

	/**
	 * 获取ID
	 *
	 * @return ID
	 */
	public final String getId() {
		return getClass().getAnnotation(Component.class).value();
	}

	/**
	 * 获取名称
	 *
	 * @return 名称
	 */
	public abstract String getName();

	/**
	 * 获取版本
	 *
	 * @return 版本
	 */
	public abstract String getVersion();

	public List<PluginAttribute> getAttributeKeys() {
		List<PluginAttribute> data = new ArrayList<>();
		return data;
	}

	/**
	 * 获取商品资料
	 * @return {"return_code", "0001","error_msg","获取商品资料出错"},{"return_code", "0000",其了支付要的参数};
	 */
	public abstract List<MarketProduct> getProducts(SysPlugin sysPlugin, List<String> skuList);

	/**
	 * 发货接口
	 * @return {"return_code", "0001","error_msg","获取商品资料出错"},{"return_code", "0000",其了支付要的参数};
	 */
//	public abstract void shipping(SysPlugin sysPlugin, Shipping shipping);


	public HttpClient createSSLHttpClient(SysPlugin sysPlugin,HttpServletRequest request) throws Exception {

		//指定读取证书格式为PKCS12
		KeyStore keyStore = KeyStore.getInstance("PKCS12");
		String rootPath = request.getSession().getServletContext().getRealPath("/");

		//读取本机存放的PKCS12证书文件
		String  method = sysPlugin.getAttribute("method");
		String mchId = sysPlugin.getMchId();

		if ("1".equals(method)) {
			SysFile sysFile = sysFileService.findById(sysPlugin.getAttribute("pkcs"));
			ByteArrayInputStream instream = new ByteArrayInputStream(sysFile.getContent());
			//指定PKCS12的密码(商户ID)
			keyStore.load(instream,mchId.toCharArray());
			instream.close();
		} else {
			FileInputStream instream = new FileInputStream(new File(rootPath+"/WEB-INF/classes/cert/"+getId()+".p12"));
			//指定PKCS12的密码(商户ID)
			keyStore.load(instream,mchId.toCharArray());
			instream.close();
		}

		SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore,mchId.toCharArray()).build();

		//指定TLS版本
		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
				sslcontext,new String[] { "TLSv1" },null,
				SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		//设置httpclient的SSLSocketFactory
		CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

		return httpclient;
	}

	/**
	 * 连接Map键值对
	 * @param map Map
	 * @param separator 连接符
	 * @param ignoreEmptyValue 忽略空值
	 * @param ignoreKeys 忽略Key
	 * @return 字符串
	 */
	protected String joinKeyValue(Map<String, Object> map,String separator, boolean ignoreEmptyValue, String... ignoreKeys) {
		List<String> keys = new ArrayList<String>(map.keySet());
		Collections.sort(keys);
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = ConvertUtils.convert(map.get(key));
			if (StringUtils.isNotEmpty(key) && !ArrayUtils.contains(ignoreKeys, key) && (!ignoreEmptyValue || StringUtils.isNotEmpty(value))) {
				list.add(key + "=" + (value != null ? value : ""));
			}
		}

		return StringUtils.join(list, separator);
	}

	/**
	 * 连接Map值
	 * @param map Map
	 * @param separator 连接符
	 * @param ignoreEmptyValue 忽略空值
	 * @param ignoreKeys 忽略Key
	 * @return 字符串
	 */
	protected String joinValue(Map<String, Object> map, String separator, boolean ignoreEmptyValue, String... ignoreKeys) {
		List<String> keys = new ArrayList<String>(map.keySet());
		Collections.sort(keys);

		List<String> list = new ArrayList<String>();
		for (int i = 0; i < keys.size(); i++) {
			String key = keys.get(i);
			String value = ConvertUtils.convert(map.get(key));
			if (StringUtils.isNotEmpty(key) && !ArrayUtils.contains(ignoreKeys, key) && (!ignoreEmptyValue || StringUtils.isNotEmpty(value))) {
				list.add(value != null ? value : "");
			}
		}
		return StringUtils.join(list, separator);
	}

	/**
	 * POST请求
	 * @param url URL
	 * @param data 请求参数
	 * @return 返回结果
	 */
	public String post(String url,String data,HttpClient httpClient) {
		Assert.hasText(url);
		String result = null;
		if (httpClient==null) {
			httpClient = new DefaultHttpClient();
		}
		try {
			HttpPost httpPost = new HttpPost(url);

			httpPost.setEntity(new StringEntity(data, "UTF-8"));
			HttpResponse httpResponse = httpClient.execute(httpPost);
			HttpEntity httpEntity = httpResponse.getEntity();
			result = EntityUtils.toString(httpEntity);
			EntityUtils.consume(httpEntity);
		} catch (ClientProtocolException e) {
			log.error(e.getMessage());
		} catch (IOException e) {
			log.error(e.getMessage());
		} finally {
			httpClient.getConnectionManager().shutdown();
		}
		return result;
	}

	/**
	 * GET请求
	 * @param url URL
	 * @param parameterMap 请求参数
	 * @return 返回结果
	 */
	public String get(String url, Map<String, Object> parameterMap) {
		Assert.hasText(url);
		String result = null;
		@SuppressWarnings("resource")
		HttpClient httpClient = new DefaultHttpClient();
		try {
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
			if (parameterMap != null) {
				for (Entry<String, Object> entry : parameterMap.entrySet()) {
					String name = entry.getKey();
					String value = ConvertUtils.convert(entry.getValue());
					if (StringUtils.isNotEmpty(name)) {
						nameValuePairs.add(new BasicNameValuePair(name, value));
					}
				}
			}
			HttpGet httpGet = new HttpGet(url + (StringUtils.contains(url, "?") ? "&" : "?") + EntityUtils.toString(new UrlEncodedFormEntity(nameValuePairs, "UTF-8")));
			HttpResponse httpResponse = httpClient.execute(httpGet);
			HttpEntity httpEntity = httpResponse.getEntity();
			result = EntityUtils.toString(httpEntity, "UTF-8");
			EntityUtils.consume(httpEntity);
		} catch (ClientProtocolException e) {
			log.error(e.getMessage());
		} catch (IOException e) {
			log.error(e.getMessage());
		} finally {
			httpClient.getConnectionManager().shutdown();
		}
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		if (this == obj) {
			return true;
		}
		PaymentPlugin other = (PaymentPlugin) obj;
		return new EqualsBuilder().append(getId(), other.getId()).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder(17, 37).append(getId()).toHashCode();
	}

	public int compareTo(PaymentPlugin paymentPlugin) {
		return new CompareToBuilder().append(getId(), paymentPlugin.getId()).toComparison();
	}



}